/* * Copyright © 2020-2024 spj * Released under the MIT License. */
(function (global, factory) {
  typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
  typeof define === 'function' && define.amd ? define(factory) :
  (global = global || self, global['scroll-view'] = factory());
}(this, function () { 'use strict';

  function _defineProperty(obj, key, value) {
    if (key in obj) {
      Object.defineProperty(obj, key, {
        value: value,
        enumerable: true,
        configurable: true,
        writable: true
      });
    } else {
      obj[key] = value;
    }

    return obj;
  }

  function ownKeys(object, enumerableOnly) {
    var keys = Object.keys(object);

    if (Object.getOwnPropertySymbols) {
      var symbols = Object.getOwnPropertySymbols(object);
      if (enumerableOnly) symbols = symbols.filter(function (sym) {
        return Object.getOwnPropertyDescriptor(object, sym).enumerable;
      });
      keys.push.apply(keys, symbols);
    }

    return keys;
  }

  function _objectSpread2(target) {
    for (var i = 1; i < arguments.length; i++) {
      var source = arguments[i] != null ? arguments[i] : {};

      if (i % 2) {
        ownKeys(source, true).forEach(function (key) {
          _defineProperty(target, key, source[key]);
        });
      } else if (Object.getOwnPropertyDescriptors) {
        Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
      } else {
        ownKeys(source).forEach(function (key) {
          Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
        });
      }
    }

    return target;
  }

  //
  //
  //
  //
  //
  //
  //
  //
  //
  //
  //

  /**
   * 组件说明
   * 横向滚动时,当前组件样式需要加   display: flex;flex-wrap: nowrap; white-space: nowrap;子项需要添加 display: inline-block;
   * 竖向滚动时候，需要给当前组件添加一个固定高度
   *
   */
  var script = {
    name: 'ScrollView',
    props: {
      /**
       * 是否是联动滚动
       */
      linkageScroll: {
        type: Boolean,
        default: false
      },
      scrollIntoViewId: {
        type: String,
        default: ''
      },
      scrollY: {
        type: Boolean,
        default: true
      },
      scrollX: {
        type: Boolean,
        default: false
      },

      /**
       * 滚动类别 "auto" | "smooth";
       */
      scrollType: {
        type: String,
        default: 'smooth'
      },

      /**
       * 滚动区域高度（横向）
       */
      scrollHeight: {
        type: Number,
        default: undefined
      },

      /**
       * 滚动区域高度（属性）
       */
      scrollWidth: {
        type: Number,
        default: undefined
      },

      /**
       * 自定义的样式
       */
      customClass: {
        type: String,
        default: ''
      },
      observeInterval: {
        type: Number,
        default: 1000
      },

      /**
       * 触发加载更多时的距离（即提前触发的距离）默认为10
       */
      onLoadMoreDistance: {
        type: Number,
        default: 10
      }
    },
    data: function data() {
      return {
        scrollViewId: '',
        scrollElement: undefined,
        childCount: 0,
        currentScrollX: false,
        currentScrollY: true,
        loading: false
      };
    },
    computed: {
      /**
       * 样式
       * @return {{"overflow-x": (string), "overflow-y": (string)}}
       */
      scrollStyle: function scrollStyle() {
        var style = {
          'overflow-y': this.currentScrollY ? 'scroll' : 'hidden',
          'overflow-x': this.currentScrollX ? 'scroll' : 'hidden'
        };

        if (this.scrollHeight) {
          style.height = this.scrollHeight + 'px';
        }

        if (this.scrollWidth) {
          style.width = this.scrollWidth + 'px';
        }

        return style;
      }
    },
    watch: {
      scrollIntoViewId: function scrollIntoViewId(newVal, oldVal) {
        this.scrollIntoView(newVal, this.scrollType);
      },
      scrollX: function scrollX(newVal, oldVal) {
        if (newVal) {
          this.currentScrollY = false;
        }
      },
      scrollY: function scrollY(newVal, oldVal) {
        if (newVal) {
          this.currentScrollX = false;
        }
      }
    },
    created: function created() {
      var randomNum = Math.floor(Math.random() * 1000);
      var dataStr = String(new Date().getTime()).substr(6);
      this.scrollViewId = 'scroll' + randomNum + dataStr;
    },
    mounted: function mounted() {
      var _this = this;

      this.currentScrollY = this.scrollY;

      if (this.scrollX) {
        // 传了横向滚动之后,自动竖向关掉
        this.currentScrollY = false;
        this.currentScrollX = this.scrollX;
      }

      this.initScrollView();

      if (this.scrollIntoViewId) {
        this.$nextTick(function () {
          return _this.scrollIntoView(_this.scrollIntoViewId, 'auto');
        });
      }
    },
    beforeDestroy: function beforeDestroy() {
      var _this2 = this;

      if (this.scrollElement) {
        var removeKeys = ['DOMSubtreeModified', 'touchstart', 'touchmove'];
        removeKeys.forEach(function (eventKey) {
          _this2.scrollElement.removeEventListener(eventKey, function (e) {});
        });
      }

      if (this.observer) {
        this.observer.disconnect();
        this.observer = undefined;
      }
    },
    methods: {
      getElement: function getElement() {
        return this.$refs.scrollView;
      },
      getComputedStyle: function (_getComputedStyle) {
        function getComputedStyle(_x) {
          return _getComputedStyle.apply(this, arguments);
        }

        getComputedStyle.toString = function () {
          return _getComputedStyle.toString();
        };

        return getComputedStyle;
      }(function (element) {
        if (window.getComputedStyle) {
          return getComputedStyle(element, null);
        } else {
          return element.currentStyle; // 兼容IE的写法
        }
      }),
      initScrollView: function initScrollView() {
        var _this3 = this;

        var element = document.getElementById(this.scrollViewId);

        if (!element) {
          return;
        }

        this.scrollElement = element;
        var clientWidth = element.clientWidth; // 页面可视宽度

        var clientHeight = element.clientHeight; // 页面可视区域的高度

        element.onscroll = function (e) {
          var scrollInfo = {};

          if (_this3.linkageScroll) {
            // 计算当前滚动的位置Id
            scrollInfo = _this3.getCurrentScrollInfo(element);
          }

          if (_this3.currentScrollY) {
            var scrollTop = element.scrollTop; // 页面上卷的高度

            var scrollHeight = element.scrollHeight; // 页面总高度

            _this3.$emit('onScroll', _objectSpread2({
              scrollHeight: scrollHeight,
              clientHeight: clientHeight,
              scrollTop: scrollTop
            }, scrollInfo));

            if (element.scrollTop + element.clientHeight + _this3.onLoadMoreDistance >= element.scrollHeight) {
              _this3.onLoadMore();
            }

            if (scrollTop === 0) {
              _this3.onRefresh();
            }
          } else if (_this3.currentScrollX) {
            var scrollLeft = element.scrollLeft;
            var scrollWidth = element.scrollWidth; // 页面总宽度

            _this3.$emit('onScroll', _objectSpread2({
              scrollWidth: scrollWidth,
              clientWidth: clientWidth,
              scrollLeft: scrollLeft
            }, scrollInfo));

            if (element.scrollLeft + clientWidth + _this3.onLoadMoreDistance >= element.scrollWidth) {
              // 要修正像素
              _this3.onLoadMore();
            }

            if (scrollLeft === 0) {
              _this3.onRefresh();
            }
          }
        }; // element.addEventListener("scroll", onscroll);//等效


        this.addDOMSubtreeModifiedListener(element, clientHeight, clientWidth);
        this.smartTouchScrollHandler();
      },
      scrollIntoView: function scrollIntoView(elementId) {
        var scrollType = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'auto';
        var distance = this.getScrollDistance(elementId);

        if (distance !== undefined) {
          if (this.currentScrollY) {
            this.scrollTo(0, distance, scrollType);
          } else {
            this.scrollTo(distance, 0, scrollType);
          }
        }
      },
      getScrollDistance: function getScrollDistance(elementId) {
        if (this.scrollElement && elementId) {
          var childNodes = this.scrollElement.childNodes;
          var distance = 0;
          var include = false;

          for (var i = 0, len = childNodes.length; i < len; i++) {
            if (childNodes[i].id === elementId) {
              include = true;
              break;
            } else {
              if (this.currentScrollY) {
                distance = distance + this.getElementHeight(childNodes[i]);
              } else {
                distance = distance + this.getElementWidth(childNodes[i]);
              }
            }
          }

          if (include) {
            return distance;
          }
        }

        return undefined;
      },
      scrollTo: function scrollTo(left, top, scrollType) {
        if (this.scrollElement) {
          this.scrollElement.scrollTo({
            behavior: scrollType || 'auto',
            // "auto" | "smooth";
            left: left,
            top: top
          });
        }
      },
      scrollToBottom: function scrollToBottom() {
        var scrollType = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'auto';

        if (this.currentScrollY && this.scrollElement) {
          var scrollTop = this.scrollElement.scrollHeight - this.scrollElement.clientHeight;
          this.scrollTo(0, scrollTop, scrollType);
        }
      },
      getElementWidth: function getElementWidth(element) {
        if (element instanceof Element) {
          var computedStyle = this.getComputedStyle(element);

          if (computedStyle.position.includes('fixed') || computedStyle.position.includes('absolute')) {
            return 0;
          }

          var width = element.clientWidth ? element.clientWidth : 0;
          width = width + this.getNumberFormStyleValue(computedStyle.marginLeft) + this.getNumberFormStyleValue(computedStyle.marginRight);
          return width;
        }

        return 0;
      },
      getElementHeight: function getElementHeight(element) {
        if (element instanceof Element) {
          var computedStyle = this.getComputedStyle(element);

          if (computedStyle.position.includes('fixed') || computedStyle.position.includes('absolute')) {
            return 0;
          }

          var height = element.clientHeight ? element.clientHeight : 0;
          height = height + this.getNumberFormStyleValue(computedStyle.marginTop) + this.getNumberFormStyleValue(computedStyle.marginBottom);
          return height;
        }

        return 0;
      },
      getNumberFormStyleValue: function getNumberFormStyleValue(value) {
        if (value) {
          var text = String(value).trim().replace('px', '');
          return Number.parseFloat(text);
        }

        return 0;
      },
      getScrollChildrenInfo: function getScrollChildrenInfo(element) {
        var _this4 = this;

        var height = 0;
        var width = 0;

        if (element && element instanceof Element && element.childNodes.length > 0) {
          element.childNodes.forEach(function (node) {
            height = height + _this4.getElementHeight(node);
            width = width + _this4.getElementWidth(node);
          });
        }

        return {
          width: width,
          height: height
        };
      },
      addDOMSubtreeModifiedListener: function addDOMSubtreeModifiedListener(element, clientHeight, clientWidth) {
        var _this5 = this;

        // 监听元素事件
        var MutationObserver = window.MutationObserver || window.WebKitMutationObserver;

        if (MutationObserver) {
          var MutationObserverConfig = {
            childList: true,
            subtree: true,
            characterData: true
          };
          this.observer = new MutationObserver(function (mutations) {
            return _this5.onDOMSubtreeModifiedHandler(element, clientHeight, clientWidth);
          });
          this.observer.observe(element, MutationObserverConfig);
        } else {
          element.addEventListener('DOMSubtreeModified', function (e) {
            return _this5.onDOMSubtreeModifiedHandler(element, clientHeight, clientWidth);
          });
        }
      },
      onDOMSubtreeModifiedHandler: function onDOMSubtreeModifiedHandler(element, clientHeight, clientWidth) {
        var _this6 = this;

        if (this.observeInterval === 0) {
          this.calculateHandler(element, clientHeight, clientWidth);
        } else {
          if (this.calculateTimeoutId) {
            clearTimeout(this.calculateTimeoutId);
          }

          this.calculateTimeoutId = setTimeout(function () {
            _this6.calculateTimeoutId = undefined;

            _this6.calculateHandler(element, clientHeight, clientWidth);
          }, this.observeInterval > 0 ? this.observeInterval : 1000);
        }
      },
      calculateHandler: function calculateHandler(element, clientHeight, clientWidth) {
        var scrollInfo = this.getScrollInfo(element, clientHeight, clientWidth);
        this.$emit('change', scrollInfo);
      },
      getScrollInfo: function getScrollInfo(element, clientHeight, clientWidth) {
        var childrenInfo = this.getScrollChildrenInfo(element);
        return {
          childrenHeight: childrenInfo.height,
          childrenWidth: childrenInfo.width,
          scrollHeight: element.scrollHeight,
          scrollWidth: element.scrollWidth,
          clientHeight: clientHeight,
          clientWidth: clientWidth
        };
      },
      onLoadMore: function onLoadMore() {
        var _this7 = this;

        // 防抖
        if (!this.loading) {
          this.loading = true;
          this.$emit('loadMore', {});
          setTimeout(function () {
            _this7.loading = false;
          }, 400);
        }
      },
      onRefresh: function onRefresh() {
        var _this8 = this;

        // 防抖
        if (!this.refreshing) {
          this.refreshing = true;
          this.$emit('refresh', {});
          setTimeout(function () {
            _this8.refreshing = false;
          }, 400);
        }
      },
      getCurrentScrollInfo: function getCurrentScrollInfo(element) {
        if (element && element instanceof Element && element.childNodes.length > 0) {
          var distance = this.currentScrollY ? element.scrollTop : element.scrollLeft;
          var currentDistance = 0;
          var info = {
            scrollId: 0,
            scrollIndex: 0
          };
          var childNodes = element.childNodes;

          for (var i = 0, len = childNodes.length; i < len; i++) {
            if (this.currentScrollY) {
              currentDistance = currentDistance + this.getElementHeight(childNodes[i]);
            } else {
              currentDistance = currentDistance + this.getElementWidth(childNodes[i]);
            }

            if (currentDistance > distance) {
              info.scrollId = childNodes[i].id;
              info.scrollIndex = i;
              return info;
            }
          } // 没有满足条件的,直接返回最后一个元素


          info.scrollIndex = childNodes.length - 1;
          info.scrollId = childNodes[info.scrollIndex].id;
          return info;
        }

        return undefined;
      },
      smartTouchScrollHandler: function smartTouchScrollHandler() {
        var _this9 = this;

        if (this.scrollElement) {
          var startX;
          var startY;
          this.scrollElement.addEventListener('touchstart', function (event) {
            startX = event.targetTouches[0].pageX;
            startY = event.targetTouches[0].pageY;
          });
          this.scrollElement.addEventListener('touchmove', function (event) {
            var position = event.targetTouches[0];

            if (startX === position.pageX && _this9.currentScrollY || startY === position.pageY && _this9.currentScrollX) {
              _this9.stopEvent(event); // 消费当前事件

            }

            startX = position.pageX;
            startY = position.pageY;
          });
        }
      },
      stopEvent: function stopEvent(event) {
        if (event) {
          if (event.stopPropagation) {
            event.stopPropagation();
          } else {
            event.cancelBubble = true;
          }
        }
      }
    }
  };

  function normalizeComponent(template, style, script, scopeId, isFunctionalTemplate, moduleIdentifier
  /* server only */
  , shadowMode, createInjector, createInjectorSSR, createInjectorShadow) {
    if (typeof shadowMode !== 'boolean') {
      createInjectorSSR = createInjector;
      createInjector = shadowMode;
      shadowMode = false;
    } // Vue.extend constructor export interop.


    var options = typeof script === 'function' ? script.options : script; // render functions

    if (template && template.render) {
      options.render = template.render;
      options.staticRenderFns = template.staticRenderFns;
      options._compiled = true; // functional template

      if (isFunctionalTemplate) {
        options.functional = true;
      }
    } // scopedId


    if (scopeId) {
      options._scopeId = scopeId;
    }

    var hook;

    if (moduleIdentifier) {
      // server build
      hook = function hook(context) {
        // 2.3 injection
        context = context || // cached call
        this.$vnode && this.$vnode.ssrContext || // stateful
        this.parent && this.parent.$vnode && this.parent.$vnode.ssrContext; // functional
        // 2.2 with runInNewContext: true

        if (!context && typeof __VUE_SSR_CONTEXT__ !== 'undefined') {
          context = __VUE_SSR_CONTEXT__;
        } // inject component styles


        if (style) {
          style.call(this, createInjectorSSR(context));
        } // register component module identifier for async chunk inference


        if (context && context._registeredComponents) {
          context._registeredComponents.add(moduleIdentifier);
        }
      }; // used by ssr in case component is cached and beforeCreate
      // never gets called


      options._ssrRegister = hook;
    } else if (style) {
      hook = shadowMode ? function () {
        style.call(this, createInjectorShadow(this.$root.$options.shadowRoot));
      } : function (context) {
        style.call(this, createInjector(context));
      };
    }

    if (hook) {
      if (options.functional) {
        // register for functional component in vue file
        var originalRender = options.render;

        options.render = function renderWithStyleInjection(h, context) {
          hook.call(context);
          return originalRender(h, context);
        };
      } else {
        // inject component registration as beforeCreate hook
        var existing = options.beforeCreate;
        options.beforeCreate = existing ? [].concat(existing, hook) : [hook];
      }
    }

    return script;
  }

  var normalizeComponent_1 = normalizeComponent;

  /* script */
  var __vue_script__ = script;
  /* template */
  var __vue_render__ = function() {
    var _vm = this;
    var _h = _vm.$createElement;
    var _c = _vm._self._c || _h;
    return _c(
      "div",
      {
        ref: "scrollView",
        staticClass: "sv-default-scroll",
        class: _vm.customClass,
        style: _vm.scrollStyle,
        attrs: { id: _vm.scrollViewId }
      },
      [_vm._t("default")],
      2
    )
  };
  var __vue_staticRenderFns__ = [];
  __vue_render__._withStripped = true;

    /* style */
    var __vue_inject_styles__ = undefined;
    /* scoped */
    var __vue_scope_id__ = undefined;
    /* module identifier */
    var __vue_module_identifier__ = undefined;
    /* functional template */
    var __vue_is_functional_template__ = false;
    /* style inject */
    
    /* style inject SSR */
    

    
    var ScrollView = normalizeComponent_1(
      { render: __vue_render__, staticRenderFns: __vue_staticRenderFns__ },
      __vue_inject_styles__,
      __vue_script__,
      __vue_scope_id__,
      __vue_is_functional_template__,
      __vue_module_identifier__,
      undefined,
      undefined
    );

  ScrollView.install = function (vue) {
    vue.component(ScrollView.name, ScrollView);
  };

  return ScrollView;

}));
